#pragma once

#include <iostream>
#include <string>
#include <sys/types.h>
#include <memory>
#include <functional>
#include "Common.hpp"
#include "Connection.hpp"
#include "Log.hpp"
#include "InetAddr.hpp"

using namespace LogModule;

#define SIZE 1024

class Channel : public Connection
{
public:
    Channel(int sockfd, const InetAddr& client)
        :_sockfd(sockfd)
        ,_client_addr(client)
    {
        SetNonBlock(_sockfd);
    }

    int GetSockFd() override
    {
        return _sockfd;
    }

    //从普通套接字读取数据添加到缓冲区
    void Recver() override
    {
        char buffer[SIZE];
        while(1)
        {
            buffer[0] = 0;
            //n表示实际读取的字节数
            ssize_t n = recv(_sockfd, buffer, sizeof(buffer) - 1, 0);
            if(n > 0)
            {
                buffer[n] = 0;
                _intbuffer += buffer;
            }
            else
            {
                if(errno == EAGAIN || errno == EWOULDBLOCK) //非阻塞查询：数据没有准备好
                {
                    LOG(LogLevel::DEBUG) << "no data ready, normal sockfd exit recver!";
                    break;
                }
                else if(errno == EINTR) //被信号打断
                {
                    continue;
                }
                else //读取数据出错
                {
                    Excepter();
                    return;
                }
            }
        }

        //数据读取完就应该要处理了
        LOG(LogLevel::DEBUG) << "Channel: Inbuffer: \n" << _intbuffer;
        //处理数据，协议的任务

        //处理接收缓冲区的数据
        if(!_intbuffer.empty())
            _outbuffer += _handler(_intbuffer);


        //发送数据，发送条件默认就绪
        if(!_outbuffer.empty())
        {
            Sender();
        }
        
    }

    void Sender() override
    {
        while(1)
        {
            ssize_t n = send(_sockfd, _outbuffer.c_str(), _outbuffer.size(), 0);
            if(n > 0)
            {
                _outbuffer.erase(0, n);
                if(_outbuffer.empty())
                    break;
            }
            else
            {
                //发送缓冲区已满
                if(errno == EAGAIN || errno == EWOULDBLOCK)
                    break;
                else if(errno == EINTR)
                    continue;
                else
                {
                    Excepter();
                    return;
                }
            }

            //代码运行至次有两种情况
            //1.数据发送完毕，关闭对写事件的关心
            //2.发送缓冲区被写满，需要开启epoll对写事件的关心
            if(!_outbuffer.empty())
            {
                GetOwner()->EnableReadWrite(_sockfd, true, true);
            }
            else
            {
                GetOwner()->EnableReadWrite(_sockfd, true, false);
            }

        }
    }

    void Excepter() override
    {}
    
private:
    int _sockfd;
    std::string _outbuffer;    //缓冲区
    std::string _intbuffer;
    InetAddr _client_addr;
};